use std::thread;
use std::time::Duration;

use futures::channel::mpsc;
use futures::executor::ThreadPool;
use futures::{executor, StreamExt};

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_features() {
        start();
    }
}

pub fn start() {
    let pool = ThreadPool::new().expect("Failed to build pool");
    let (tx, rx) = mpsc::unbounded::<i32>();

    let fut_values = async {
        // Create another async block, again where the Future implementation
        // is generated by async. Since this is inside of a parent async block,
        // it will be provided with the executor of the parent block when the parent
        // block is executed.
        //
        // This executor chaining is done by Future::poll whose second argument
        // is a std::task::Context. This represents our executor, and the Future
        // implemented by this async block can be polled using the parent async
        // block's executor.
        let fut_tx_result = async move {
            (0..100).for_each(|v| {
                tx.unbounded_send(v).expect("Failed to send");
            })
        };

        // Use the provided thread pool to spawn the generated future
        // responsible for transmission
        pool.spawn_ok(fut_tx_result);

        let fut_values = rx.map(|v| v * 2).collect();

        // Use the executor provided to this async block to wait for the
        // future to complete.
        fut_values.await
    };

    // Actually execute the above future, which will invoke Future::poll and
    // subsequenty chain appropriate Future::poll and methods needing executors
    // to drive all futures. Eventually fut_values will be driven to completion.
    let values: Vec<i32> = executor::block_on(fut_values);
    println!("{:?}", values);
}
